#include <algorithm/analytical_model/io/json/converter/shared/data/scene/Heliostat.h>
#include <algorithm/analytical_model/io/json/converter/shared/data/topology/geometry/Geometry.h>
#include <algorithm/analytical_model/io/json/converter/shared/utils/Vec2.h>

using namespace solar;

void solar::tag_invoke(const boost::json::value_from_tag& /*unused*/,
                       boost::json::value& json_value, const Heliostat& heliostat)
{
    auto geometry_ptr = SOLAR_GET_VALUE(Heliostat, geometry_, heliostat);
    auto gap = SOLAR_GET_VALUE(Heliostat, gap_, heliostat);
    auto subhelio_row_col = SOLAR_GET_VALUE(Heliostat, subhelio_row_col_, heliostat);
    auto has_brace = SOLAR_GET_VALUE(Heliostat, has_brace_, heliostat);
    json_value = {
        {             "gap",              boost::json::value_from(gap)},
        {"subhelio_row_col", boost::json::value_from(subhelio_row_col)},
        {       "has_brace",                                 has_brace}
    };
    if (solar::hasValue(geometry_ptr))
    {
        json_value.emplace_object()["geometry"] = boost::json::value_from(geometry_ptr);
    }
}

auto solar::tag_invoke(const boost::json::value_to_tag<Heliostat>& /*unused*/,
                       const boost::json::value& json_value) -> Heliostat
{
    const auto* value_ptr = json_value.if_object();
    if (value_ptr == nullptr)
    {
        return {};
    }
    Heliostat result;
    if (const auto* geometry_value = value_ptr->if_contains("geometry"); geometry_value != nullptr)
    {
        SOLAR_SET_VALUE(Heliostat, geometry_,
                        boost::json::value_to<std::shared_ptr<Geometry>>(*geometry_value), result)
    }
    if (const auto* gap_value = value_ptr->if_contains("gap"); gap_value != nullptr)
    {
        SOLAR_SET_VALUE(Heliostat, gap_, boost::json::value_to<Vec2>(*gap_value), result)
    }
    if (const auto* subhelio_row_col_value = value_ptr->if_contains("subhelio_row_col");
        subhelio_row_col_value != nullptr)
    {
        SOLAR_SET_VALUE(Heliostat, subhelio_row_col_,
                        boost::json::value_to<Vec2>(*subhelio_row_col_value), result)
    }
    if (const auto* has_brace_value = value_ptr->if_contains("has_brace");
        has_brace_value != nullptr)
    {
        SOLAR_SET_VALUE(Heliostat, has_brace_, has_brace_value->get_bool(), result)
    }

    return result;
}
